package hust.hbhmzy.udpchat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.HashMap;

import android.content.SharedPreferences;
import android.util.Log;

public class ContactManager {

	private static final String LOG_TAG = "ContactManager";
	public static final int BROADCAST_PORT = 50001; // 接收与发送 “ADD+name，ip” “BYE”
	private static final int BROADCAST_INTERVAL = 10000; // 毫秒
	private static final int BROADCAST_BUF_SIZE = 1024;
	private boolean BROADCAST = true;
	private boolean LISTEN = true;
	private HashMap<String, InetAddress> contacts; //每一个contact存放 name 与 ip
	private InetAddress broadcastIP;
	private String name;
	
	public ContactManager(String name, InetAddress broadcastIP) {
		
		contacts = new HashMap<String, InetAddress>();
		this.broadcastIP = broadcastIP;
		this.name = name;
		listen();
		broadcastName(name, broadcastIP);
	}

	//在重新回到主页面的时候，调用此方法。
	public void  restart(){
		listen();
		broadcastName(name, broadcastIP);
	}
	//点击通知好友 按钮时，播报自身 name与ip。
	public void  rebroad(){
		broadcastName(name, broadcastIP);
	}
	
	public HashMap<String, InetAddress> getContacts() {
		return contacts;
	}


	//添加收到的 好友，但需要判断是否是自身，或者是否已经存在。
	public void addContact(String name, InetAddress address) {
		if(name.equals(this.name)){
			Log.e(LOG_TAG, "we have same name" );
		}else{
		//	判断是否已经存在好友
			if(!contacts.containsKey(name)) {

				Log.i(LOG_TAG, "Adding contact: " + name);
				contacts.put(name, address);
				Log.i(LOG_TAG, "#Contacts: " + contacts.size());

			}else{
				Log.i(LOG_TAG, "Contact already exists: " + name);
				Log.i(LOG_TAG, "Contact size " + String.valueOf(contacts.size()));
			}
		}
	}
	//移除好友
	public void removeContact(String name) {
		//如果好友存在于contacts中，就移除他
		if(contacts.containsKey(name)) {
			
			Log.i(LOG_TAG, "Removing contact: " + name);
			contacts.remove(name);
			Log.i(LOG_TAG, "#Contacts: " + contacts.size());
			return;
		}
		Log.i(LOG_TAG, "Cannot remove contact. " + name + " does not exist.");
		return;
	}
	
	public void bye(final String name) {
		// 发送BYE消息，通知移除好友
		Thread byeThread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				try {
					Log.i(LOG_TAG, "Attempting to broadcast BYE notification!");
					String notification = "BYE:"+name;
					byte[] message = notification.getBytes();
					DatagramSocket socket = new DatagramSocket();
					socket.setBroadcast(true);
					DatagramPacket packet = new DatagramPacket(message, message.length, broadcastIP, BROADCAST_PORT);
					socket.send(packet);
					Log.i(LOG_TAG, "Broadcast BYE notification!");
					socket.disconnect();
					socket.close();
					return;
				}
				catch(SocketException e) {
					
					Log.e(LOG_TAG, "SocketException during BYE notification: " + e);
				}
				catch(IOException e) {
					
					Log.e(LOG_TAG, "IOException during BYE notification: " + e);
				}
			}
		});
		byeThread.start();
	}
	//播报自身 name 与ip，
	public void broadcastName(final String name, final InetAddress broadcastIP) {
		// 以固定间隔广播设备的名称
		Log.i(LOG_TAG, "Broadcasting started!");
		Thread broadcastThread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					String request = "ADD:"+name;
					byte[] message = request.getBytes();
					DatagramSocket socket = new DatagramSocket();
					socket.setBroadcast(true);
					DatagramPacket packet = new DatagramPacket(message, message.length, broadcastIP, BROADCAST_PORT);
					while(BROADCAST) {
						
						socket.send(packet);
						Log.i(LOG_TAG, "Broadcast packet sent: " + packet.getAddress().toString());
						Thread.sleep(BROADCAST_INTERVAL);
					}
					Log.i(LOG_TAG, "Broadcaster ending!");
					socket.disconnect();
					socket.close();
					return;
				}
				catch(SocketException e) {
					
					Log.e(LOG_TAG, "SocketExceltion in broadcast: " + e);
					Log.i(LOG_TAG, "Broadcaster ending!");
					return;
				}
				catch(IOException e) {
					
					Log.e(LOG_TAG, "IOException in broadcast: " + e);
					Log.i(LOG_TAG, "Broadcaster ending!");
					return;
				}
				catch(InterruptedException e) {
					
					Log.e(LOG_TAG, "InterruptedException in broadcast: " + e);
					Log.i(LOG_TAG, "Broadcaster ending!");
					return;
				}
			}
		});
		broadcastThread.start();
	}
	
	public void stopBroadcasting() {
		// 结束播报线程
		BROADCAST = false;
	}
	
	public void listen() {
		// 开启监听线程
		Log.i(LOG_TAG, "Listening started!");
		Thread listenThread = new Thread(new Runnable() {

			@Override
			public void run() {
				
				DatagramSocket socket;
				try {
					
					socket = new DatagramSocket(BROADCAST_PORT);
				} 
				catch (SocketException e) {
					
					Log.e(LOG_TAG, "SocketExcepion in listener: " + e);
					return;
				}
				byte[] buffer = new byte[BROADCAST_BUF_SIZE];
					
				while(LISTEN) {
					
					listen(socket, buffer);
				}
				Log.i(LOG_TAG, "Listener ending!");
				socket.disconnect();
				socket.close();
				return;
			}
			
			public void listen(DatagramSocket socket, byte[] buffer) {

				try {
					//Listen in for new notifications
					Log.i(LOG_TAG, "Listening for a packet!");
					DatagramPacket packet = new DatagramPacket(buffer, BROADCAST_BUF_SIZE);
					socket.setSoTimeout(15000);
					socket.receive(packet);
					String data = new String(buffer, 0, packet.getLength());
					Log.i(LOG_TAG, "Packet received: " + data);
					String action = data.substring(0, 4);
					if(action.equals("ADD:")) {
						// 接收到 ADD消息，将此添加到contacts中
						Log.i(LOG_TAG, "Listener received ADD request");
						addContact(data.substring(4, data.length()), packet.getAddress());
					}
					else if(action.equals("BYE:")) {
						// 接收到 BYE消息，将此从contacts中删除
						Log.i(LOG_TAG, "Listener received BYE request");
						removeContact(data.substring(4, data.length()));
					}
					else {
						// Invalid notification received
						Log.w(LOG_TAG, "Listener received invalid request: " + action);
					}
					
				}
				catch(SocketTimeoutException e) {
					
					Log.i(LOG_TAG, "No packet received!");
					if(LISTEN) {
					
						listen(socket, buffer);
					}
					return;
				}
				catch(SocketException e) {
					
					Log.e(LOG_TAG, "SocketException in listen: " + e);
					Log.i(LOG_TAG, "Listener ending!");
					return;
				}
				catch(IOException e) {
					
					Log.e(LOG_TAG, "IOException in listen: " + e);
					Log.i(LOG_TAG, "Listener ending!");
					return;
				}
			}
		});
		listenThread.start();
	}
	
	public void stopListening() {
		// Stops the listener thread
		LISTEN = false;
	}
}
